import phonenumbers
from typing import Tuple, Dict, Optional, List
from dataclasses import dataclass
from phonenumbers import PhoneNumberFormat
from phonenumbers.phonenumberutil import NumberParseException

@dataclass
class PhoneRegion:
    """手机号区域信息"""
    code: str                # 国际区号
    country_code: str        # 国家代码
    name_zh: str            # 中文名称
    name_en: str            # 英文名称
    example_number: str     # 示例号码

class PhoneValidator:
    """手机号验证器 - 基于 Google's libphonenumber"""
    
    # 常用地区信息
    PHONE_REGIONS: Dict[str, PhoneRegion] = {
        # 亚洲
        "86": PhoneRegion("86", "CN", "中国大陆", "China", "13812345678"),
        "852": PhoneRegion("852", "HK", "中国香港", "Hong Kong", "51234567"),
        "853": PhoneRegion("853", "MO", "中国澳门", "Macau", "66123456"),
        "886": PhoneRegion("886", "TW", "中国台湾", "Taiwan", "0912345678"),
        "65": PhoneRegion("65", "SG", "新加坡", "Singapore", "91234567"),
        "60": PhoneRegion("60", "MY", "马来西亚", "Malaysia", "123456789"),
        "81": PhoneRegion("81", "JP", "日本", "Japan", "09012345678"),
        "82": PhoneRegion("82", "KR", "韩国", "South Korea", "1012345678"),
        "66": PhoneRegion("66", "TH", "泰国", "Thailand", "812345678"),
        "84": PhoneRegion("84", "VN", "越南", "Vietnam", "912345678"),
        "62": PhoneRegion("62", "ID", "印度尼西亚", "Indonesia", "812345678"),
        "63": PhoneRegion("63", "PH", "菲律宾", "Philippines", "9123456789"),
        "91": PhoneRegion("91", "IN", "印度", "India", "9123456789"),
        
        # 北美
        "1": PhoneRegion("1", "US", "美国", "United States", "2123456789"),
        "1": PhoneRegion("1", "CA", "加拿大", "Canada", "2123456789"),
        
        # 欧洲
        "44": PhoneRegion("44", "GB", "英国", "United Kingdom", "7123456789"),
        "33": PhoneRegion("33", "FR", "法国", "France", "612345678"),
        "49": PhoneRegion("49", "DE", "德国", "Germany", "15123456789"),
        "39": PhoneRegion("39", "IT", "意大利", "Italy", "3123456789"),
        "34": PhoneRegion("34", "ES", "西班牙", "Spain", "612345678"),
        "31": PhoneRegion("31", "NL", "荷兰", "Netherlands", "612345678"),
        "46": PhoneRegion("46", "SE", "瑞典", "Sweden", "701234567"),
        "47": PhoneRegion("47", "NO", "挪威", "Norway", "41234567"),
        
        # 大洋洲
        "61": PhoneRegion("61", "AU", "澳大利亚", "Australia", "412345678"),
        "64": PhoneRegion("64", "NZ", "新西兰", "New Zealand", "211234567"),
        
        # 中东
        "971": PhoneRegion("971", "AE", "阿联酋", "United Arab Emirates", "501234567"),
        "966": PhoneRegion("966", "SA", "沙特阿拉伯", "Saudi Arabia", "512345678"),
        "972": PhoneRegion("972", "IL", "以色列", "Israel", "501234567"),
        
        # 其他
        "7": PhoneRegion("7", "RU", "俄罗斯", "Russia", "9123456789"),
        "55": PhoneRegion("55", "BR", "巴西", "Brazil", "11987654321"),
        "52": PhoneRegion("52", "MX", "墨西哥", "Mexico", "1234567890"),
    }

    @classmethod
    def parse_phone(cls, phone: str) -> Tuple[Optional[str], Optional[str]]:
        """
        解析手机号，返回区号和号码
        :param phone: 完整手机号（包含区号）
        :return: (区号, 手机号) 元组
        """
        try:
            # 如果没有指定区号，默认使用中国大陆
            if not phone.startswith('+'):
                phone = '+86' + phone
            
            parsed = phonenumbers.parse(phone)
            return str(parsed.country_code), str(parsed.national_number)
        except NumberParseException:
            return None, None

    @classmethod
    def validate_phone(cls, phone: str) -> Tuple[bool, Optional[str], Optional[PhoneRegion]]:
        """
        验证手机号是否有效
        :param phone: 完整手机号（包含区号）
        :return: (是否有效, 错误信息, 区域信息) 元组
        """
        try:
            # 如果没有指定区号，默认使用中国大陆
            if not phone.startswith('+'):
                phone = '+86' + phone
            
            # 解析电话号码
            parsed = phonenumbers.parse(phone)
            
            # 验证号码
            if not phonenumbers.is_valid_number(parsed):
                return False, "无效的电话号码格式", None
            
            # 验证是否是手机号
            if phonenumbers.number_type(parsed) != phonenumbers.PhoneNumberType.MOBILE:
                return False, "不是有效的手机号码", None
            
            # 获取区域信息
            code = str(parsed.country_code)
            region = cls.PHONE_REGIONS.get(code)
            if not region:
                region = PhoneRegion(
                    code=code,
                    country_code=phonenumbers.region_code_for_number(parsed),
                    name_zh=phonenumbers.region_code_for_number(parsed),  # 暂时使用英文
                    name_en=phonenumbers.region_code_for_number(parsed),
                    example_number=phonenumbers.format_number(
                        phonenumbers.example_number_for_type(
                            phonenumbers.region_code_for_number(parsed),
                            phonenumbers.PhoneNumberType.MOBILE
                        ),
                        PhoneNumberFormat.NATIONAL
                    )
                )
            
            return True, None, region
            
        except NumberParseException as e:
            return False, str(e), None

    @classmethod
    def format_phone(cls, phone: str, format_type: str = 'INTERNATIONAL') -> Optional[str]:
        """
        格式化手机号
        :param phone: 完整手机号（包含区号）
        :param format_type: 格式化类型 (INTERNATIONAL/NATIONAL/E164)
        :return: 格式化后的手机号，如果无效返回None
        """
        try:
            # 如果没有指定区号，默认使用中国大陆
            if not phone.startswith('+'):
                phone = '+86' + phone
            
            parsed = phonenumbers.parse(phone)
            if not phonenumbers.is_valid_number(parsed):
                return None
            
            format_map = {
                'INTERNATIONAL': PhoneNumberFormat.INTERNATIONAL,
                'NATIONAL': PhoneNumberFormat.NATIONAL,
                'E164': PhoneNumberFormat.E164
            }
            return phonenumbers.format_number(parsed, format_map.get(format_type, PhoneNumberFormat.INTERNATIONAL))
            
        except NumberParseException:
            return None

    @classmethod
    def get_region_by_code(cls, code: str) -> Optional[PhoneRegion]:
        """
        根据区号获取区域信息
        :param code: 国际区号
        :return: 区域信息对象
        """
        return cls.PHONE_REGIONS.get(code)

    @classmethod
    def list_supported_regions(cls) -> List[PhoneRegion]:
        """
        获取所有支持的区域信息
        :return: 区域信息列表
        """
        regions = []
        for region_code in phonenumbers.SUPPORTED_REGIONS:
            try:
                example = phonenumbers.example_number_for_type(
                    region_code,
                    phonenumbers.PhoneNumberType.MOBILE
                )
                if example:
                    code = str(example.country_code)
                    if code in cls.PHONE_REGIONS:
                        regions.append(cls.PHONE_REGIONS[code])
                    else:
                        regions.append(PhoneRegion(
                            code=code,
                            country_code=region_code,
                            name_zh=region_code,  # 暂时使用英文
                            name_en=region_code,
                            example_number=phonenumbers.format_number(
                                example,
                                PhoneNumberFormat.NATIONAL
                            )
                        ))
            except Exception:
                continue
        return regions 
    
# 使用示例
# 验证手机号
# is_valid, error_msg, region = PhoneValidator.validate_phone("+8613812345678")
# is_valid, error_msg, region = PhoneValidator.validate_phone("13812345678")  # 自动添加+86

# # 格式化手机号
# formatted = PhoneValidator.format_phone("+8613812345678", "INTERNATIONAL")  # +86 138 1234 5678
# formatted = PhoneValidator.format_phone("+8613812345678", "NATIONAL")      # 138 1234 5678
# formatted = PhoneValidator.format_phone("+8613812345678", "E164")         # +8613812345678

# # 获取所有支持的地区
# regions = PhoneValidator.list_supported_regions()   